#include "genMips.h"

void initVariableADeclarer()
{
	int i;
	nbVariableADeclarer = 0;
	
	for(i=0;i<GENMIPS_VARIABLE_NBDECLARATIONMAX;i++)
	{
		varaibleADeclarer[i] = NULL;
	}
}

void ajoutVariableADeclarer(entree element)
{	
	char * buffer = malloc(sizeof(char) * 256);
	
	if(nbVariableADeclarer >= GENMIPS_VARIABLE_NBDECLARATIONMAX)
	{
		printf("Erreur : ajoutVariableADeclarer : table variableADeclarer pleine.\n");
		exit(-1);
	}
	else
	{
		if(element.valeur.type == ENTREE_TYPECTE_ENTIER)
		{
			sprintf(buffer,"%s:	.word	0\n",element.nom);
		}
		else if(element.valeur.type == ENTREE_TYPECTE_CHAR)
		{
			sprintf(buffer,"%s:	.asciiz	\"%s\"\n",element.nom,element.valeur.valeurChar);						
		}
		else
		{
			printf("Erreur : ajoutVariableADeclarer : type entree constante incorrect.\n");
			exit(-1);
		}
		
		varaibleADeclarer[nbVariableADeclarer] = buffer;
		nbVariableADeclarer++;
	}
}

void initPourGestionPile()
{
	int i;
	nbPourGestionPile = 0;
	pointeurPourGestionPile = 0;
	maxPointeurPourGestionPile = 0;
	
	for(i=0;i<GENMIPS_TAILLEMAXPILE;i++)
	{
		varaibleADeclarer[i] = NULL;
	}
	
	marquerPourGestionPile();
}

int ajoutPourGestionPile(char * nom)
{
	char * bufferItoA;
	int t1,t2;
	
	if(nbVariableADeclarer >= GENMIPS_VARIABLE_NBDECLARATIONMAX)
	{
		printf("Erreur : ajoutPourGestionPile : table pourGestionPile pleine.\n");
		exit(-1);
	}
	
	t1 = nbPourGestionPile;
	t2 = pointeurPourGestionPile;
	pourGestionPile[nbPourGestionPile] = nom;
	nbPourGestionPile++;
	pointeurPourGestionPile += 4;
	
	if(maxPointeurPourGestionPile < pointeurPourGestionPile)
	{
		maxPointeurPourGestionPile = pointeurPourGestionPile;
	}
	
	bufferItoA = calloc (16, sizeof(char));
	sprintf(bufferItoA,"%d",t2);
	ajoutTableGencode("chargeDansLaPile",nom,bufferItoA,"");
	
	return t1;
}

void suppressionPourGestionPile()
{
	char * bufferItoA;
	char * nom;

	if(strcmp(pourGestionPile[nbPourGestionPile - 1],"_marqueur") == 0)
	{
		printf("Erreur : suppressionPourGestionPile : suppression d'un element qui en fait est un marqueur.\n");
		exit(-1);
	}
	
	nbPourGestionPile--;
	nom = pourGestionPile[nbPourGestionPile];
	pourGestionPile[nbPourGestionPile] = NULL;
	pointeurPourGestionPile -= 4;
	
	bufferItoA = calloc (16, sizeof(char));
	sprintf(bufferItoA,"%d",pointeurPourGestionPile);
	ajoutTableGencode("chargeDeLaPile",nom,bufferItoA,"");
}

void marquerPourGestionPile()
{
	char * bufferItoA;
	
	bufferItoA = calloc (10, sizeof(char));
	sprintf(bufferItoA,"_marqueur");
	pourGestionPile[nbPourGestionPile] = bufferItoA;
	nbPourGestionPile++;
}

void suppressionMarqueurPourGestionPile()
{
	if(strcmp(pourGestionPile[nbPourGestionPile - 1],"_marqueur") != 0)
	{
		printf("Erreur : suppressionMarqueurPourGestionPile : suppression d'un marqueur qui n'en est pas un.\n");
		exit(-1);
	}
	
	nbPourGestionPile--;
	pourGestionPile[nbPourGestionPile] = NULL;
}

void affichagePourGestionPile()
{
	int i;
	printf("\nPile pour gérer la pile mips :\n");
	for(i=nbPourGestionPile-1; i>=0; i--)
	{
		printf("\t%s\n",pourGestionPile[i]);
	}
	printf("\n");
}

void mipsGeneration(FILE * out)
{
	dataGeneration(out);
	textGeneration(out);
}

void dataGeneration (FILE * out)
{
	int i;
	//char * clef;
	//entree element;
	//pChaineChaineEntreeNode ligne;
	
	fprintf(out,".data\n");
	fprintf(out,"\tsys_retour_ligne:	.asciiz	\"\\n\"\n");
	
	/*
	for(i=0; i<HASH_TABLE_SIZE; i++)
	{
		if(existeIndexHashTable(i))
		{
			ligne = recupLigneHashTable(i);
			while(!chaineChaineEntreeNodeEstNull(ligne))
			{
				if(cibleChaineChaineEntreeNode(ligne) != NULL)
				{
					clef = clefChaineChaineEntreeNode(ligne);
					element = consulteHashTable(clef);
					
					if(element.typeEntree == ENTREE_TYPEENTREE_CTE)
					{
						if(element.valeur.type == ENTREE_TYPECTE_ENTIER)
						{
							fprintf(out,"%s:	.word	%d\n",clef,element.valeur.valeurIntBool);
						}
						else if(element.valeur.type == ENTREE_TYPECTE_CHAR)
						{
							fprintf(out,"%s:	.asciiz	\"%s\"",clef,element.valeur.valeurChar);						
						}
						else
						{
							printf("Erreur : dataGeneration : type entree constante incorrect.\n");
							exit(-1);
						}
					}
				}
				else
				{
					fprintf(out,"%s:	.word\n",clef);
				}
				
				ligne = nextChaineChaineEntreeNode(clefChaineChaineEntreeNode(ligne));
			}
		}
	}
	*/
	
	for(i=0;i<nbVariableADeclarer;i++)
	{
		fprintf(out,"%s\n",varaibleADeclarer[i]);	
	}
	
	fprintf(out,"\n");
}

void textGeneration (FILE * out)
{
	int i;
	
	fprintf(out,".text\n.globl main\n\nmain :\n");
	
	//création de la pile
	fprintf(out,"li $s0,%d\n",maxPointeurPourGestionPile);
	fprintf(out,"sub $sp, $sp, $s0\n");
	
	for(i=0;i<nbElementGencode;i++)
	{
		if(strcmp(tableGencode[i]->commande,"addition") == 0)
		{
			codeAdditionGeneration(out,i);
		}
		else if(strcmp(tableGencode[i]->commande,"multiplication") == 0)
		{
			codeMultiplicationGeneration(out,i);
		}
		else if(strcmp(tableGencode[i]->commande,"moinsUnaire") == 0)
		{
			codeMoinsUnaireGeneration(out,i);
		}
		else if(strcmp(tableGencode[i]->commande,"affectation") == 0)
		{
			codeAffectationGeneration(out,i);
		}
		else if(strcmp(tableGencode[i]->commande,"affectationVal") == 0)
		{
			codeAffectationValGeneration(out,i);
		}
		else if(strcmp(tableGencode[i]->commande,"ecriture") == 0)
		{
			codeEcritureGeneration(out,i);
		}
		else if(strcmp(tableGencode[i]->commande,"ecritureVal") == 0)
		{
			codeEcritureValGeneration(out,i);
		}
		else if(strcmp(tableGencode[i]->commande,"chargeDansLaPile") == 0)
		{
			codeChargeDanslaPileGeneration(out,i);
		}
		else if(strcmp(tableGencode[i]->commande,"chargeDeLaPile") == 0)
		{
			codeChargeDeLaPileGeneration(out,i);
		}
		else 
		{
			printf("Erreur : textGeneration : commande inconnue (%s)\n",tableGencode[i]->commande);
			exit(-1);
		}
	}
	
	fprintf(out,"\tli $v0, 10	#fin du programme\n\tsyscall\n");
}

void codeAdditionGeneration (FILE * out, int indexGenMips)
{
	char * retour = tableGencode[indexGenMips]->adresse1;
	char * source1 = tableGencode[indexGenMips]->adresse2;
	char * source2 = tableGencode[indexGenMips]->adresse3;
	
	fprintf(out,"\tlw $t0, %s	#id := id + id\n",source1);
	fprintf(out,"\tlw $t1, %s\n",source2);
	fprintf(out,"\tadd $t0, $t0, $t1\n");
	fprintf(out,"\tsw $t0, %s\n",retour);
	fprintf(out,"\n");
}

void codeMultiplicationGeneration (FILE * out, int indexGenMips)
{
	char * retour = tableGencode[indexGenMips]->adresse1;
	char * source1 = tableGencode[indexGenMips]->adresse2;
	char * source2 = tableGencode[indexGenMips]->adresse3;
	
	fprintf(out,"\tlw $t0, %s	#id := id * id\n",source1);
	fprintf(out,"\tlw $t1, %s\n",source2);
	fprintf(out,"\tmul $t0, $t0, $t1\n");
	fprintf(out,"\tsw $t0, %s\n",retour);
	fprintf(out,"\n");
}

void codeMoinsUnaireGeneration (FILE * out, int indexGenMips)
{
	char * retour = tableGencode[indexGenMips]->adresse1;
	char * source1 = tableGencode[indexGenMips]->adresse2;
	
	fprintf(out,"\tlw $t0, %s	#id := id * id\n",source1);
	fprintf(out,"\tli $t1, -1\n");
	fprintf(out,"\tmul $t0, $t0, $t1\n");
	fprintf(out,"\tsw $t0, %s\n",retour);
	fprintf(out,"\n");
}

void codeAffectationGeneration (FILE * out, int indexGenMips)
{
	char * retour = tableGencode[indexGenMips]->adresse1;
	char * source = tableGencode[indexGenMips]->adresse2;
	
	fprintf(out,"\tlw $t0, %s	#id := id\n",source);
	fprintf(out,"\tsw $t0, %s\n",retour);
	fprintf(out,"\n");
}

void codeAffectationValGeneration (FILE * out, int indexGenMips)
{
	char * retour = tableGencode[indexGenMips]->adresse1;
	char * source = tableGencode[indexGenMips]->adresse2;
	
	fprintf(out,"\tli $t0, %s	#id := (int)\n",source);
	fprintf(out,"\tsw $t0, %s\n",retour);
	fprintf(out,"\n");
}

void codeEcritureGeneration (FILE * out, int indexGenMips)
{
	char * source = tableGencode[indexGenMips]->adresse1;
	
	/*if(consulteHashTable(source).valeur.type == ENTREE_TYPECTE_CHAR)
	{
		fprintf(out,"\tli $v0,4		#print id_char\n");
		fprintf(out,"\tla $a0,%s\n",source);
		fprintf(out,"\tsyscall\n");
		fprintf(out,"\tli $v0,4\n");
		fprintf(out,"\tla $a0,sys_retour_ligne\n");
		fprintf(out,"\tsyscall\n");
		fprintf(out,"\n");
	}
	else if(consulteHashTable(source).valeur.type == ENTREE_TYPECTE_ENTIER)
	{*/
		fprintf(out,"\tli, $v0,1		#print id_int\n");
		fprintf(out,"\tlw $a0,%s\n",source);
		fprintf(out,"\tsyscall\n");
		fprintf(out,"\tli $v0,4\n");
		fprintf(out,"\tla $a0,sys_retour_ligne\n");
		fprintf(out,"\tsyscall\n");
		fprintf(out,"\n");
	/*}
	else
	{
		printf("Erreur : codeEcritureGeneration : type constante non reconnu.\n");
		exit(-1);
	}*/
}

void codeEcritureValGeneration (FILE * out, int indexGenMips)
{
	char * source = tableGencode[indexGenMips]->adresse1;

	fprintf(out,"\tli $v0,1		#print (int)\n");
	fprintf(out,"\tli $a0,%s\n",source);
	fprintf(out,"\tsyscall\n");
	fprintf(out,"\tli $v0,4\n");
	fprintf(out,"\tla $a0,sys_retour_ligne\n");
	fprintf(out,"\tsyscall\n");
	fprintf(out,"\n");
}

void codeChargeDanslaPileGeneration (FILE * out, int indexGenMips)
{
	char * source = tableGencode[indexGenMips]->adresse1;
	char * decalage = tableGencode[indexGenMips]->adresse2;
	
	fprintf(out,"\tlw $t0, %s\n	#charge %s dans la pile",source,source);
	fprintf(out,"\tsw $t0, %s($sp)\n",decalage);
}

void codeChargeDeLaPileGeneration (FILE * out, int indexGenMips)
{
	char * destination = tableGencode[indexGenMips]->adresse1;
	char * decalage = tableGencode[indexGenMips]->adresse2;
	
	fprintf(out,"\tlw $t0, %s($sp)\n	#charge dans %s la pile",decalage,destination);
	fprintf(out,"\tsw $t0, %s\n",destination);
}
	
